package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import com.tianji.learning.constants.RedisConstants;

import javax.validation.constraints.Min;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author 赵博凯
 * @since 2025-10-29
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {


    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;

    @Override
    public PointsBoardVO pageQueryBySeason(PointsBoardQuery query) {
        //1、判断是否是查询当前赛季
        Long season = query.getSeason();
        boolean isCurrentSeason = ObjectUtils.isNull(season) || season == 0;

        String key = RedisConstants.POINTS_BOARDS_KEY_PREFIX + LocalDate.now().format(DateUtils.DATE_SUFFIX_FORMATTER);

        //2、查询我的榜单信息（当前赛季 || 历史赛季）
        PointsBoard myBoard = isCurrentSeason ?
                queryMyCurrentBoard(key) :
                queryMyHistoryBoard(season);


        //3、查询排行榜列表信息（当前赛季 || 历史赛季）
        List<PointsBoard> boards = isCurrentSeason ?
                queryCurrentBoardList(key, query.getPageNo(), query.getPageSize()) :
                queryHistoryBoardList(query);


        //4、封装数据
        PointsBoardVO vo = new PointsBoardVO();
        //4.1、封装我的榜单信息
        vo.setRank(myBoard.getRank());
        vo.setPoints(myBoard.getPoints());

        //4.2、封装排行榜列表信息
        if(ObjectUtils.isEmpty(boards)){
            return vo;
        }
        //4.2.2.1、查询用户信息
        Set<Long> userIds = CollStreamUtil.toSet(boards, PointsBoard::getUserId);
        List<UserDTO> userInfoList = userClient.queryUserByIds(userIds);
        Map<Long, String> userNameMap = new HashMap<>(userInfoList.size());
        if(ObjectUtils.isNotEmpty(userInfoList)){
            userNameMap = CollStreamUtil.toMap(userInfoList, UserDTO::getId, UserDTO::getName);
        }

        //4.2.2.2、循环组装voList
        List<PointsBoardItemVO> boardList = new ArrayList<>(boards.size());
        for(PointsBoard board : boards){
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            itemVO.setRank(board.getRank());
            itemVO.setPoints(board.getPoints());
            itemVO.setName(userNameMap.get(board.getUserId()));
            boardList.add(itemVO);
        }
        vo.setBoardList(boardList);
        // 5、返回数据
        return vo;
    }

    @Override
    public void createPointsBoardTableBySeason(Integer season) {
        getBaseMapper().createPointsBoardTable(POINTS_BOARD_TABLE_PREFIX + season);
    }

    private List<PointsBoard> queryHistoryBoardList(PointsBoardQuery query) {
        return null;
    }

    private List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {
        //1、分页查询
        int start = (pageNo - 1) * pageSize, end = start + pageSize - 1;
        Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if(ObjectUtils.isEmpty(tuples)){
            return CollUtils.emptyList();
        }

        //2、封装榜单列表并返回
        List<PointsBoard> list = new ArrayList<>(tuples.size());
        int rank = start + 1;
        for(ZSetOperations.TypedTuple<String> tuple : tuples){
            String userId = tuple.getValue();
            Double points = tuple.getScore();
            if(ObjectUtils.isNull(userId) || ObjectUtils.isNull(points)){
                continue;
            }
            PointsBoard board = new PointsBoard();
            board.setUserId(Long.valueOf(userId));
            board.setPoints(points.intValue());
            board.setRank(rank++);
            list.add(board);
        }
        return list;
    }

    private PointsBoard queryMyHistoryBoard(Long season) {
        return null;
    }

    private PointsBoard queryMyCurrentBoard(String key) {
        String userId = UserContext.getUser().toString();

        //1、绑定key
        BoundZSetOperations<String, String> zSetOps = redisTemplate.boundZSetOps(key);

        //2、从redis zset中查询我的 排名
        Long rank = zSetOps.reverseRank(userId);

        //3、从redis zset中查询我的积分
        Double points = zSetOps.score(userId);


        //4、封装数据
        PointsBoard myBoard = new PointsBoard();
        myBoard.setRank(ObjectUtils.isNull(rank) ? 0 :rank.intValue() + 1);
        myBoard.setPoints(ObjectUtils.isNull(points) ? 0 :points.intValue());
        return myBoard;
    }


}
